package zbl.c0.inter;

/**
 * 		指令栈，用于存放生成的所有指令
 * @author 朱伯龙
 *
 */

public class CodeStack {

	private static int MAX_DEPTH = 1000;		//  最大栈深，即指令最多的数目
	
	private static Pcode[] code;				//  指令栈，每条指令对应一个串
	
	private static int top;						//  当前栈顶指针
	
	
	/**
	 * 		进行必要的初始化操作
	 */
	public CodeStack(){
		code = new Pcode[MAX_DEPTH];
		top = 1;								//  0 用来返填main函数的调用语句
	}
	
	/**
	 * 		返填main函数的调用语句
	 * @param main_addr
	 */
	public void reverWrt(int main_addr){
		code[0] = new Pcode("CAL", 0, main_addr);
	}
	
	/**
	 * 		生成指定的代码串，并保存到code[]中
	 */
	private void emit(String op, int l, int a){
		if(top < MAX_DEPTH)						//  检测是否代码栈溢出
		{
			code[top] = new Pcode(op, l, a);
			top++;
		}else{
			System.out.println("代码栈溢出，无法添加当前指令！！！");
		}
	}
	
	/**
	 * 		返回指定位置的指令串
	 * @param addr
	 * @return
	 */
	public Pcode getOp(int addr){
		return code[addr];
	}
	
	//##################  具体生成代码的方法族     ####################
	
	/**
	 * 		取常量 value 放到运算栈栈顶
	 * @param value		需要放到栈顶的常量（整数）
	 */
	public void genLIT(int value){
		emit("LIT", 0, value);
	}
	
	/**
	 * 		执行运算,opKind表示执行何种运算
	 * @param opKind	表示执行何种运算
	 */
	public void genOPR(int opKind){
		emit("OPR", 0, opKind);
	}
	
	/**
	 * 		条件转移到a
	 * 该指令对进行  运算栈  次栈顶<RelationOP>栈顶  的检测
	 * 
	 * 如果为真则pc计数器保持不变程序顺序执行
	 * 如果为假则pc计数器指向跳转到的指令处顺序执行
	 * 
	 * 注意执行完成JPC指令后一定要将运算栈的栈顶和次栈顶清空，即top = top-2;
	 * 
	 * @param l		测试条件代码<RelationOP>
	 * @param a		跳转地址
	 */
	public void genJPC(int l,int a){
		emit("JPC", l, a);
	}
	
	/**
	 * 		将栈顶内容输出
	 * @param l			l==0  表示输出的是当前运算栈栈顶的元素，  l==1  表示要输出字符串
	 * @param a			要输出的字符串在常量串中的位置
	 * 
	 * 对应这样的  printf  ‘(‘ <Strings> , <Expression> ‘)’语句要按顺序生成两条指令
	 * 时刻注意保持运算栈的平衡。
	 *  
	 **/
	public void genWRT(int l, int a){
		emit("WRT", l, a);
	}
	
	/**
	 * 		LOD	l,a  取变量放到运算栈顶
	 * @param l		层次差
	 * @param a		相对地址
	 */
	public void genLOD(int l, int a){
		emit("LOD", l, a);
	}
	
	/**
	 * 		将运算栈栈顶内容存入变量
	 * @param l		相对地址
	 * @param a		层次差
	 */
	public void genSTO(int l, int a){
		emit("STO", l, a);
	}
	
	/**
	 * 		调用过程
	 * @param a		入口地址
	 * 
	 */
	public void genCAL(int a){
		emit("CAL", 0, a);
	}
	
	/**
	 * 		读数据并存入变量
	 * @param l		l==0表示是函数内的变量，l==1表示是全局变量
	 * @param a		a表示变量的相对地址
	 * 
	 */
	public void genRED(int l, int a){
		emit("RED", l, a);
	}
	
	/**
	 * 		函数返回指令
	 *   a=0表示一般函数返回,a=1表示main函数返回
	 */
	public void genRET(int a){
		emit("RET", 0, a);
	}
	
	/**
	 * 		控制运算栈的栈顶指针减1
	 * @param a
	 */
	public void genINT(int a){
		emit("INT", 0 ,a);
	}
	/**
	 * 		返回当前代码栈的栈顶地址
	 * @return
	 */
	public int getTop(){
		return top;
	}
	
	/**
	 * 		回填addr位置指令的  a属性
	 * @param addr
	 * @param value
	 */
	public void tracerAddr(int addr, int value){
		if(addr >= top)
		{
			System.out.println("回填越界！！");
		}
		code[addr].a = value;
	}
	
	//################################################################
	/**
	 * 		显示代码栈的信息
	 */
	public void showStack(){
		System.out.println("########Code Stack########");
		for(int i=0; i<top; i++)
			System.out.println(i+"   :   "+code[i].toString());
		System.out.println("##########################");
	}
	
	
	/**
	 * For testing...............
	 */
	
	/*
	public static void main(String args[]){
		CodeStack testCode = new CodeStack();
		testCode.genJMP(10);
		testCode.genCAL(0, 20);
		testCode.genADD(20);
		testCode.showStack();
	}
	*/
}